import json
import traceback
import pymongo
from bson import json_util

import service
from config.config import db


class MongoConn:
    def __init__(self, db_name):
        # connect db
        try:
            self.conn = pymongo.MongoClient(db.get("host"), db.get("port"))
            self.db = self.conn[db_name]  # connect db
            # self.username=MONGODB_CONFIG['username']
            # self.password=MONGODB_CONFIG['password']
            # if self.username and self.password:
            #     self.connected = self.db.authenticate(self.username, self.password)
            # else:
            self.connected = True
        except Exception:
            print(traceback.format_exc())
            print('Connect Statics Database Fail.')
            # sys.exit(1)


class MongoTable:
    def __init__(self, table_name, db_name='tao'):
        self.table_name = table_name
        self.db_name = db_name
        self.db = service.mongo_service

    def find_one(self, value):
        return self.db.find_one(self.table_name, value)

    def find(self, value):
        return self.db.find(self.table_name, value)


class MongoService:
    def __init__(self, db_name='tao'):
        self.db_name = db_name

    @staticmethod
    def check_connected(conn):
        # 检查是否连接成功
        if not conn.connected:
            raise NameError('stat:connected Error')

    def save(self, table, value):
        # 一次操作一条记录，根据‘_id’是否存在，决定插入或更新记录
        try:
            my_conn = MongoConn(self.db_name)
            self.check_connected(my_conn)
            my_conn.db[table].save(value)
        except Exception:
            print(traceback.format_exc())

    def aggregate(self, table, value):
        try:
            my_conn = MongoConn(self.db_name)
            self.check_connected(my_conn)
            return my_conn.db[table].aggregate(value)
        except Exception:
            print(traceback.format_exc())

    def insert(self, table, value):
        # 可以使用insert直接一次性向mongoDB插入整个列表，也可以插入单条记录，但是'_id'重复会报错
        try:
            my_conn = MongoConn(self.db_name)
            self.check_connected(my_conn)
            my_conn.db[table].insert(value, continue_on_error=True)
        except Exception:
            print(traceback.format_exc())

    def update(self, table, conditions, value, s_upsert=False, s_multi=False):
        my_conn = MongoConn(self.db_name)
        self.check_connected(my_conn)
        return my_conn.db[table].update(conditions, value, upsert=s_upsert, multi=s_multi)

    def upsert_mary(self, table, datas):
        # 批量更新插入，根据‘_id’更新或插入多条记录。
        # 把'_id'值不存在的记录，插入数据库。'_id'值存在，则更新记录。
        # 如果更新的字段在mongo中不存在，则直接新增一个字段
        try:
            my_conn = MongoConn(self.db_name)
            self.check_connected(my_conn)
            bulk = my_conn.db[table].initialize_ordered_bulk_op()
            for data in datas:
                _id = data['_id']
                bulk.find({'_id': _id}).upsert().update({'$set': data})
            bulk.execute()
        except Exception:
            print(traceback.format_exc())

    def upsert_one(self, table, data):
        # 更新插入，根据‘_id’更新一条记录，如果‘_id’的值不存在，则插入一条记录
        try:
            my_conn = MongoConn(self.db_name)
            self.check_connected(my_conn)
            query = {'_id': data.get('_id', '')}
            if not my_conn.db[table].find_one(query):
                my_conn.db[table].insert(data)
            else:
                data.pop('_id')  # 删除'_id'键
                my_conn.db[table].update(query, {'$set': data})
        except Exception:
            print(traceback.format_exc())

    @staticmethod
    def toJsonStr(docs):
        is_dict = False
        for key in docs:
            if type(key) == dict:
                is_dict = True
            break
        if is_dict:
            _dict = [json.loads(
                json.dumps(key, sort_keys=False, indent=0, default=json_util.default, ensure_ascii=False))]
            for key in docs:
                _dict.append(json.loads(
                    json.dumps(key, sort_keys=False, indent=0, default=json_util.default, ensure_ascii=False)))
            return _dict

        return json.loads(json.dumps(docs, sort_keys=False, indent=0, default=json_util.default, ensure_ascii=False))

    @staticmethod
    def to_json(docs):
        is_dict = False
        for key in docs:
            if type(key) == dict:
                is_dict = True
            break

        if is_dict:
            _dict = [
                json.dumps(key, sort_keys=False, indent=0, default=json_util.default, ensure_ascii=False)]
            for key in docs:
                _dict.append(json.loads(
                    json.dumps(key, sort_keys=False, indent=0, default=json_util.default, ensure_ascii=False)))
            return _dict

        return json.dumps(docs, sort_keys=False, indent=0, default=json_util.default, ensure_ascii=False)

    def find_one(self, table, value):
        # 根据条件进行查询，返回一条记录
        try:
            my_conn = MongoConn(self.db_name)
            self.check_connected(my_conn)
            doc = my_conn.db[table].find_one(value)
            return doc
        except Exception:
            print(traceback.format_exc())

    def find(self, table, value):
        # 根据条件进行查询，返回所有记录
        try:
            my_conn = MongoConn(self.db_name)
            self.check_connected(my_conn)
            docs = my_conn.db[table].find(value)
            return docs
        except Exception:
            print(traceback.format_exc())

    def select_colum(self, table, value, colum):
        # 查询指定列的所有值
        try:
            my_conn = MongoConn(self.db_name)
            self.check_connected(my_conn)
            return my_conn.db[table].find(value, colum)
        except Exception:
            print(traceback.format_exc())

            # def __init__(self):
            #     self.client = MongoClient(db.get("host"), db.get("port"))
            #     self.db = self.client.tao  # Select the database
            #     self.devices = self.db.devices  # Select the collection
            #     self.users = self.db.users  # Select the collection
            #     self.settings = self.db.settings  # device setting
            #     self.way_point = self.db.way_point  # Select the collection

            # def getUserInfo(self, openid):
            #     return self.devices.find_one({'sn': openid})
            #
            # def setUserInfo(self, info):
            #     self.users.update({'openid': info['openid']}, {'$set': info})
